package com.yuneec.fly.presenters;

import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;

import com.yuneec.droneservice.ConnectionListener;
import com.yuneec.droneservice.ServiceManager;
import com.yuneec.droneservice.command.CommandListener;
import com.yuneec.droneservice.command.GetCameraInfo;
import com.yuneec.droneservice.command.GetChannelValues;
import com.yuneec.droneservice.command.GetControllerGPS;
import com.yuneec.droneservice.command.GetControllerVersion;
import com.yuneec.droneservice.command.GetJoystickValue;
import com.yuneec.droneservice.model.CameraInfo;
import com.yuneec.droneservice.model.ControllerLocation;
import com.yuneec.droneservice.model.ControllerVersion;
import com.yuneec.droneservice.model.JoystickValues;
import com.yuneec.droneservice.parse.DroneFeedback;
import com.yuneec.droneservice.request.IRequest;
import com.yuneec.droneservice.request.IResponse;
import com.yuneec.droneservice.request.OnListener;
import com.yuneec.fly.DroneApplication;
import com.yuneec.fly.GlobalParams;
import com.yuneec.fly.R;
import com.yuneec.fly.events.EventBusFactory;
import com.yuneec.fly.events.commandEvent.ChangeStatusEvent;
import com.yuneec.fly.events.commandEvent.SendCommandEvent;
import com.yuneec.fly.events.uiEvent.CameraConnectChangedEvent;
import com.yuneec.fly.events.uiEvent.ConnectionChangeEvent;
import com.yuneec.fly.events.uiEvent.DroneDisconnectedEvent;
import com.yuneec.fly.events.uiEvent.DroneReconnectedEvent;
import com.yuneec.fly.events.uiEvent.SetControllerLocationEvent;
import com.yuneec.fly.events.uiEvent.SetDroneLocationEvent;
import com.yuneec.fly.utils.LogUtils;

import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import static com.yuneec.fly.GlobalParams.stopAllCommand;


/**
 * Created by jw.gu on 2016/6/12.
 */
public class DronePresenter {
    private static final int CHECK_CONNECT_STATUS = 111;

    private static DronePresenter instance;
    public boolean TXRunSuccess;
    private ServiceManager serviceManager = ServiceManager.getInstance();
    //    private FlightLog flightLog;
    private boolean running;
    private boolean connected;
    public WarningPresenter warningPresenter;
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (!running) {
                return;
            }
            switch (msg.what) {
                case CHECK_CONNECT_STATUS:
                    if (GlobalParams.lastDroneFeedbackTime != 0) {
                        if (SystemClock.elapsedRealtime() - GlobalParams.lastDroneFeedbackTime > 10000 && GlobalParams.droneConnected) {
                            setDroneConnected(false);
                            if (warningPresenter != null) {
                                warningPresenter.reset();
                            }
                            EventBusFactory.getUiBus().post(new DroneDisconnectedEvent());
                        } else if (SystemClock.elapsedRealtime() - GlobalParams.lastDroneFeedbackTime < 10000 && !GlobalParams.droneConnected) {
                            setDroneConnected(true);
                            EventBusFactory.getUiBus().post(new DroneReconnectedEvent());
                        }
                    }
                    handler.sendEmptyMessageDelayed(CHECK_CONNECT_STATUS, 500);
                    break;
            }
        }
    };

    private DronePresenter() {
        warningPresenter = new WarningPresenter(DroneApplication.getApplication());
//        flightLog = FlightLog.getInstance();
    }

    public static DronePresenter getInstance() {
        if (instance == null) {
            synchronized (Cgo3ProPresenter.class) {
                if (instance == null) {
                    instance = new DronePresenter();
                }
            }
        }
        return instance;
    }

    public void initService() {
        Log.d("zzd", "initService");
        TXRunSuccess = false;
        if (!EventBusFactory.getCommandBus().isRegistered(this)) {
            EventBusFactory.getCommandBus().register(this);
        }
        if (warningPresenter != null) {
            warningPresenter.reset();
        }
        ServiceManager.getInstance().init(DroneApplication.getApplication(), new ServiceManager.InitCompleteListener() {
            @Override
            public void onInitComplete() {
                running = true;
                initServiceListener(ServiceManager.getInstance());
                handler.sendEmptyMessageDelayed(CHECK_CONNECT_STATUS, 500);
            }
        });
        if (!EventBusFactory.getUiBus().isRegistered(DroneApplication.getApplication())) {
            EventBusFactory.getUiBus().register(DroneApplication.getApplication());
        }
    }

    public void exit() {
        SystemClock.sleep(100);
        if (EventBusFactory.getCommandBus().isRegistered(this)) {
            EventBusFactory.getCommandBus().unregister(this);
        }
        running = false;
        serviceManager.unInit();
        serviceManager = null;
        GlobalParams.lastDroneFeedbackTime = 0;
//        flightLog.closedFlightNote(true);
        if (EventBusFactory.getUiBus().isRegistered(DroneApplication.getApplication())) {
            EventBusFactory.getUiBus().unregister(DroneApplication.getApplication());
        }
    }


    private void initServiceListener(ServiceManager serviceManager) {
        serviceManager.addDroneFeedbackListener(new DroneFeedbackListenerImpl());
        serviceManager.addPayloadByPassListener(new PayloadByPassListenerImpl());
        serviceManager.addConnectionListener(new ConnectionListenerImpl());
        serviceManager.addControllerFeedbackListener(ConstantPresenter.getInstance());
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (running) {
                    sendCommand(new GetChannelValues(), new CommandListener<int[]>() {
                        @Override
                        public void onSuccess(IResponse<int[]> response) {
                            ConstantPresenter.getInstance().setChannels(response.getParam());
                        }
                    });
                    SystemClock.sleep(500);
                }
            }
        }).start();

//        MavLinkProtocolPlugin.addMavLinkReceive(new OnListener<ByteBuf>() {
//            @Override
//            public void onListener(ByteBuf byteBuf) {
//                Log.d("zzd_aoa","receive mavlink drone package!");
//            }
//        });
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (running) {
                    sendCommand(new GetControllerGPS(), new CommandListener<ControllerLocation>() {

                        @Override
                        public void onSuccess(IResponse<ControllerLocation> response) {
                            ControllerLocation controllerLocation = response.getParam();
                            ConstantPresenter.getInstance().setControllerLocation(response.getParam());
                            EventBusFactory.getFeedBackBus().post(new SetControllerLocationEvent(controllerLocation.latitude, controllerLocation.longitude));
                        }
                    });
                    SystemClock.sleep(200);
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (running) {
                    sendCommand(new GetJoystickValue(), new CommandListener<JoystickValues>() {
                        @Override
                        public void onSuccess(IResponse<JoystickValues> response) {
                            ConstantPresenter.getInstance().setJoystickValues(response.getParam());
                        }

                        @Override
                        public void onTimeout() {
                            super.onTimeout();
                            Log.d("zzd_aoa", "GetJoystickValue  onTimeout");
                        }

                        @Override
                        public void onError(int errorCode) {
                            super.onError(errorCode);
                            Log.d("zzd_aoa", "GetJoystickValue  onError:" + errorCode);
                        }
                    });
                    SystemClock.sleep(1000);
                }
            }
        }).start();
    }

    @Subscribe(threadMode = ThreadMode.ASYNC)
    public void sendCommand(SendCommandEvent event) {
        sendCommand(event.command, event.commandListener);
    }

    public void sendCommand(IRequest command, CommandListener listener) {
        if (!stopAllCommand) {
            if (serviceManager != null) {
                serviceManager.sendDroneCommand(command, listener);
            } else if (listener != null) {
                listener.onTimeout();
            }
        }
    }

    public synchronized void onTXRunSuccess() {
        LogUtils.e("connect drone success");
        EventBusFactory.getUiBus().post(new ChangeStatusEvent(DroneApplication.getApplication().getString(R.string.status_connected_drone)));
        TXRunSuccess = true;
        setDroneConnected(true);
    }

    private void setDroneConnected(boolean droneConnected) {
        GlobalParams.droneConnected = droneConnected;
    }

    class DroneFeedbackListenerImpl implements OnListener<DroneFeedback> {
        private long count;
        private int ss;


        @Override
        public void onListener(DroneFeedback feedback) {
            ss++;
            count++;
            if (ss > 15) {
                ss = 0;
            }
//            LogUtils.e("receive DroneFeedback "+feedback);
            GlobalParams.droneFeedback = feedback;
            GlobalParams.lastDroneFeedbackTime = SystemClock.elapsedRealtime();
            if (!TXRunSuccess) {
                onTXRunSuccess();
            }
            EventBusFactory.getUiBus().post(new SetDroneLocationEvent(feedback.latitude, feedback.longitude, feedback.yaw));
            warningPresenter.check(feedback);
        }
    }

    class PayloadByPassListenerImpl implements OnListener<byte[]> {

        @Override
        public void onListener(byte[] bytes) {
        }
    }

    public class ConnectionListenerImpl implements ConnectionListener {
        private void getCurrentCamera() {
            Log.e("zzd", "getCurrentCamera");
            EventBusFactory.getCommandBus().post(new SendCommandEvent(new GetCameraInfo(), new CommandListener<CameraInfo>() {
                @Override
                public void onSuccess(IResponse<CameraInfo> response) {
                    final CameraInfo cameraInfo = response.getParam();
                    Log.e("zzd", "getSsid: " + cameraInfo == null ? "null" : cameraInfo.getSsid());
                    if (!TextUtils.isEmpty(cameraInfo.getSsid())) {
                        GlobalParams.connectedCamera = cameraInfo.getSsid();
                        Log.e("zzd", "send camera changed!!!!!!!");
                        EventBusFactory.getUiBus().post(new CameraConnectChangedEvent());
                    }
                }

                @Override
                public void onTimeout() {
                    Log.e("zzd", "getSsid: onTimeout");
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            getCurrentCamera();
                        }
                    }, 5000);
                }

                @Override
                public void onError(int errorCode) {
                    Log.e("zzd", "getSsid: onError:" + errorCode);
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            getCurrentCamera();
                        }
                    }, 5000);
                }
            }));
        }

        private void getVersion() {
            if (!connected) {
                return;
            }
            EventBusFactory.getCommandBus().post(new SendCommandEvent(new GetControllerVersion(), new CommandListener<ControllerVersion>() {
                @Override
                public void onSuccess(IResponse<ControllerVersion> response) {
                    ConstantPresenter.getInstance().setControllerVersion(response.getParam());
                }

                @Override
                public void onError(int errorCode) {
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            getVersion();
                        }
                    }, 5000);
                }

                @Override
                public void onTimeout() {
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            getVersion();
                        }
                    }, 5000);
                }
            }));
        }

        @Override
        public void onConnected() {
            connected = true;
            ConstantPresenter.getInstance().init();
            EventBusFactory.getUiBus().post(new ConnectionChangeEvent(true));
            Log.e("zzd", "controller connected");
            getCurrentCamera();
            getVersion();
        }

        @Override
        public void onDisconnected() {
            connected = false;
            EventBusFactory.getUiBus().post(new ConnectionChangeEvent(false));
            GlobalParams.connectedCamera = null;
            GlobalParams.cameraType = null;
            Log.e("zzd", "controller disconnected");
            EventBusFactory.getUiBus().post(new CameraConnectChangedEvent());
            ConstantPresenter.getInstance().deInit();
        }
    }


}
